/**
 * @作者 7七月
 * @微信公号 林间有风
 * @开源项目 $ http://talelin.com
 * @免费专栏 $ http://course.talelin.com
 * @我的课程 $ http://imooc.com/t/4294850
 * @创建时间 2020-03-12 21:09
 */
package com.ruoyi.task.service;


import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import com.ruoyi.common.utils.StringUtils;
import lombok.Builder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLConnection;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class WxAuthenticationService {

    @Autowired
    private ObjectMapper mapper;


    @Value("${wx.code2session}")
    private String code2SessionUrl;
    @Value("${wx.appid}")
    private String appid;
    @Value("${wx.appsecret}")
    private String appsecret;

    @Value("${wx.gzhAppId}")
    private String gzhAppId;
    @Value("${wx.gzhAppSecret}")
    private String gzhAppsecret;

    @Value("${wx.phonenumber}")
    private String phonenumber;

    @Autowired
    private StringRedisTemplate redisTemplate;

    public static final String WX_ACCESE_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token";


    public static final String REDIS_KEY_ACCESS_TOKEN = "REDIS_KEY_ACCESS_TOKEN";

    public  Map<String, Object> code2Session(String code) {
        String url = MessageFormat.format(this.code2SessionUrl, this.appid, this.appsecret, code);
        RestTemplate rest = new RestTemplate();
        Map<String, Object> session = new HashMap<>();
        String sessionText = rest.getForObject(url, String.class);
        try {
            session = mapper.readValue(sessionText, Map.class);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return session;
    }

/*    public String getopenid(String code){
       // String appid= "公众号appid";
        //String secret = "公众号secret";
      //  response.setHeader("Access-Control-Allow-Origin", "*");
        *//*星号表示所有的域都可以接受，*//*
     //   response.setHeader("Access-Control-Allow-Methods", "GET,POST");
        String wxLoginUrl = "https://api.weixin.qq.com/sns/oauth2/access_token";
        String param = "appid="+appid+"&secret="+appsecret+"&code="+code+"&grant_type=authorization_code";
        String jsonString = GetPostUntil.sendGet(wxLoginUrl, param);
        JSONObject json = JSONObject.parseObject(jsonString);
        System.out.println("-------------0000-=-----= "+json.toString());
        String openid = json.getString("openid");
        return openid;
    }*/

    public  JSONObject getOpenId(String code) {

        String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appid
                + "&secret=" + appsecret + "&js_code=" + code + "&grant_type=authorization_code";
        PrintWriter out = null;
        BufferedReader in = null;
        String line;
        StringBuffer stringBuffer = new StringBuffer();
        try {
            URL realUrl = new URL(url);
            // 打开和URL之间的连接
            URLConnection conn = realUrl.openConnection();

            // 设置通用的请求属性 设置请求格式
            //设置返回类型
            conn.setRequestProperty("contentType", "text/plain");
            //设置请求类型
            conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
            //设置超时时间
            conn.setConnectTimeout(1000);
            conn.setReadTimeout(1000);
            conn.setDoOutput(true);
            conn.connect();
            // 获取URLConnection对象对应的输出流
            out = new PrintWriter(conn.getOutputStream());
            // flush输出流的缓冲
            out.flush();
            // 定义BufferedReader输入流来读取URL的响应    设置接收格式
            in = new BufferedReader(
                    new InputStreamReader(conn.getInputStream(), "UTF-8"));
            while ((line = in.readLine()) != null) {
                stringBuffer.append(line);
            }
            JSONObject jsonObject = JSONObject.parseObject(stringBuffer.toString());
            return jsonObject;

        } catch (Exception e) {
            e.printStackTrace();
        }
        //使用finally块来关闭输出流、输入流
        finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return null;
    }




   /* public String getOpenId(HttpServletRequest request, String code) {

        String content = "";
        String openId = "";
        String unionId = "";
        //封装获取openId的微信API
        StringBuffer url = new StringBuffer();
        url.append("https://api.weixin.qq.com/sns/oauth2/access_token?appid=")
                .append(appid)
                .append("&secret=")
                .append(appsecret)
                .append("&code=")
                .append(code)
                .append("&grant_type=authorization_code");

        ObjectMapper objectMapper = new ObjectMapper();
        try {
            content = HttpClient.requestGet(url.toString());
            Map map = objectMapper.readValue(content, Map.class);
            openId = String.valueOf(map.get("openid"));
            unionId = String.valueOf(map.get("unionid"));

            log.info("获取的openID：" + openId);
            *//*
             * 将openId保存到session中，当其他业务获取openId时，
             * 可先从session中获取openId.
             *//*
           // request.getSession().setAttribute("openId", openId);
        } catch (JsonParseException e) {
            log.error("json解析失败：", e);
        } catch (JsonMappingException e) {
            log.error("map转换成json失败：", e);
        } catch (Exception e) {
            log.error("http获取openId请求失败：", e);
        }
        return openId;
    }*/


    private String registerUser(Map<String, Object> session) {
        String openid = (String)session.get("openid");

      return "";
    }

    public String getWxUserPhone(String mobileCode) {
        // 获取Access_Token
        String accessToken = getAccessTokenPhone();
        // 请求解析手机号
        StringBuilder getPhoneNumberUrl = new StringBuilder(phonenumber);
        getPhoneNumberUrl.append("?access_token=").append(accessToken);
        Map<String, String> phoneNumberParam = new HashMap<>();
        phoneNumberParam.put("code", mobileCode);
        RestTemplate rest = new RestTemplate();
        ResponseEntity<HashMap> hashMapResponseEntity = rest.postForEntity(getPhoneNumberUrl.toString(), phoneNumberParam, HashMap.class);
        log.info("=== 微信手机授权请求解析手机号返回：{} ",hashMapResponseEntity.getBody());
        if (hashMapResponseEntity.getStatusCodeValue() != 200 || Objects.isNull(hashMapResponseEntity.getBody()) || (Integer) hashMapResponseEntity.getBody().get("errcode")!=0) {
            throw new RuntimeException("解析手机接口调用异常~");
        }
        //  log.info("=== 微信手机授权请求解析手机号返回：{} ",hashMapResponseEntity.getBody());
        LinkedHashMap phoneInfo = (LinkedHashMap)hashMapResponseEntity.getBody().get("phone_info");
        String purePhoneNumber = (String)phoneInfo.get("purePhoneNumber");
        return purePhoneNumber;
    }

/*    private String getAccessToken() {
        // 查询redis 是否有存放access_token避免过多次请求
        // 请求ACCESS_TOKEN
        StringBuilder accessTokenUrl = new StringBuilder(WX_ACCESE_TOKEN_URL);
        accessTokenUrl.append("?grant_type=client_credential");
        accessTokenUrl.append("&appid=").append(this.appid);
        accessTokenUrl.append("&secret=").append(this.appsecret);
        RestTemplate rest = new RestTemplate();
        ResponseEntity<HashMap> accessTokenRes = rest.getForEntity(accessTokenUrl.toString(), HashMap.class);
        if (accessTokenRes.getStatusCodeValue() != 200 || Objects.isNull(accessTokenRes.getBody()) || Objects.nonNull(accessTokenRes.getBody().get("errcode"))) {
            throw new RuntimeException("Token接口调用异常~");
        }
      //  log.info("=== 微信手机授权请求AccessToken返回：{} ",accessTokenRes.getBody());
        String accessToken = accessTokenRes.getBody().get("access_token").toString();
        // 存放redis 设置两个小时超时时间
        //redisUtil.set(REDIS_KEY_ACCESS_TOKEN,accessToken,2L, TimeUnit.HOURS);
        return accessToken;
    }*/

    public String getAccessTokenPhone() {
        // 先从Redis获取access_token
        String accessToken = redisTemplate.opsForValue().get(this.appid);
        if (StringUtils.isNotBlank(accessToken)) {
            return accessToken;
        }

        // 请求微信接口获取新的access_token
        String url = MessageFormat.format("{0}?grant_type=client_credential&appid={1}&secret={2}",
                WX_ACCESE_TOKEN_URL, this.appid, this.appsecret);

        ResponseEntity<HashMap> response = restTemplate.getForEntity(url, HashMap.class);
        if (response.getStatusCodeValue() != 200 || Objects.isNull(response.getBody())
                || Objects.nonNull(response.getBody().get("errcode"))) {
            throw new RuntimeException("获取access_token失败：" + response.getBody());
        }

        accessToken = response.getBody().get("access_token").toString();
        // 将新token存入Redis，有效期7100秒（比微信的7200稍短）
        try {
            redisTemplate.opsForValue().set(
                    this.appid,
                    accessToken,
                    7100,
                    TimeUnit.SECONDS
            );
        } catch (Exception e) {
            log.error("Redis存储access_token失败：", e);
        }
        return accessToken;
    }

    public String getAccessToken() {
        // 先从Redis获取access_token
        String accessToken = redisTemplate.opsForValue().get(this.gzhAppId);
        if (StringUtils.isNotBlank(accessToken)) {
            return accessToken;
        }

        // 请求微信接口获取新的access_token
        String url = MessageFormat.format("{0}?grant_type=client_credential&appid={1}&secret={2}",
                WX_ACCESE_TOKEN_URL, this.gzhAppId, this.gzhAppsecret);

        ResponseEntity<HashMap> response = restTemplate.getForEntity(url, HashMap.class);
        if (response.getStatusCodeValue() != 200 || Objects.isNull(response.getBody())
                || Objects.nonNull(response.getBody().get("errcode"))) {
            throw new RuntimeException("获取access_token失败：" + response.getBody());
        }

        accessToken = response.getBody().get("access_token").toString();
        // 将新token存入Redis，有效期7100秒（比微信的7200稍短）
        try {
            redisTemplate.opsForValue().set(
                    this.gzhAppId,
                    accessToken,
                    7100,
                    TimeUnit.SECONDS
            );
        } catch (Exception e) {
            log.error("Redis存储access_token失败：", e);
        }
        return accessToken;
    }

    private final RestTemplate restTemplate = new RestTemplate();
    private static final String SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s";

    /**
     * 发送模板消息
     * @param accessToken 微信access_token
     * @param message 模板消息对象
     * @return 发送结果
     */
    public WxTemplateResult sendTemplateMessage(String accessToken, TemplateMessage message) {
        String url = String.format(SEND_URL, accessToken);
        ResponseEntity<WxTemplateResult> response = restTemplate.postForEntity(url, message, WxTemplateResult.class);
        return response.getBody();
    }

    /**
     * 模板消息参数实体
     */
    @Data
    @Builder
    public static class TemplateMessage {
        private String touser;
        @JsonProperty("template_id")
        private String templateId;
        private String url;
        private MiniProgram miniprogram;
        @JsonProperty("client_msg_id")
        private String clientMsgId;
        private Map<String, TemplateDataValue> data;
    }

    /**
     * 小程序跳转参数
     */
    @Data
    public static class MiniProgram {
        private String appid;
        private String pagepath;
    }

    /**
     * 模板数据值对象
     */
    @Data
    public static class TemplateDataValue {
        private String value;
        private String color;

        public TemplateDataValue(String value) {
            this.value = value;
        }

        public TemplateDataValue(String value, String color) {
            this.value = value;
            this.color = color;
        }
    }

    /**
     * 发送结果封装
     */
    @Data
    public static class WxTemplateResult {
        private Integer errcode;
        private String errmsg;
        @JsonProperty("msgid")
        private String msgId;
    }

}
